﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;

namespace LowLevelGraphics.ColorSpaces
{
    /// <summary>
    /// YUV Channel
    /// </summary>
    public enum YUVChannel
    {
        /// <summary>
        /// 
        /// </summary>
        Y = 0,
        /// <summary>
        /// 
        /// </summary>
        U = 1,
        /// <summary>
        /// 
        /// </summary>
        V = 2
    }

    /// <summary>
    /// Class to convert RGB to YUV and back
    /// </summary>
    [DebuggerDisplay("Y: {m_Y}, U: {m_U}, V: {m_V}")]
    public class YUV : AbstractColorSpace
    {
        protected float m_Y = 0.0f;
        protected float m_U = 0.0f;
        protected float m_V = 0.0f;

        /// <summary>
        /// Primary constructor
        /// </summary>
        /// <param name="_color"></param>
        public YUV(Color _color)
            : base(_color)
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="YUV"/> class.
        /// </summary>
        /// <param name="_Y">The _ Y.</param>
        /// <param name="_U">The _ U.</param>
        /// <param name="_V">The _ V.</param>
        public YUV(float _Y, float _U, float _V)
        {
            m_Y = _Y;
            m_U = _U;
            m_V = _V;
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_yuv"></param>
        internal YUV(YUV _yuv)
        {
            this.m_Color = _yuv.m_Color;
            this.m_Y = _yuv.m_Y;
            this.m_U = _yuv.m_U;
            this.m_V = _yuv.m_V;
        }

        /// <summary>
        /// enables caller to cast a caller into this color space
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static explicit operator YUV(Color _color)
        {
            return new YUV(_color);
        }

        /// <summary>
        /// Gets or sets Y
        /// </summary>
        public float Y
        {
            get { return m_Y; }
            set { m_Y = value; }
        }

        /// <summary>
        /// Gets or sets U
        /// </summary>
        public float U
        {
            get { return m_U; }
            set { m_U = value; }
        }

        /// <summary>
        /// Gets or sets V
        /// </summary>
        public float V
        {
            get { return m_V; }
            set { m_V = value; }
        }

        /// <summary>
        /// Convert colors into this color space
        /// </summary>
        protected override void CalcValues()
        {
            m_Y = 0.299f * m_Color.R + 0.587f * m_Color.G + 0.114f * m_Color.B;
            m_U = -0.147f * m_Color.R - 0.289f * m_Color.G + 0.437f * m_Color.B;
            m_V = 0.615f * m_Color.R - 0.515f * m_Color.G - 0.100f * m_Color.B;
        }

        /// <summary>
        /// retransform colors into rgb
        /// </summary>
        /// <returns></returns>
        public override Color ToColor()
        {
            float fR = 1.0f * m_Y + 0.0f * m_U + 1.140f * m_V;
            float fG = 1.0f * m_Y - 0.394f * m_U - 0.581f * m_V;
            float fB = 1.0f * m_Y + 2.028f * m_U + 0.0f * m_V;

            if (fR < 0) fR = 0; if (fR > 255) fR = 255;
            if (fG < 0) fG = 0; if (fG > 255) fG = 255;
            if (fB < 0) fB = 0; if (fB > 255) fB = 255;
            return Color.FromArgb((int)fR, (int)fG, (int)fB);
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public override AbstractColorSpace Normalize()
        {
            m_U /= 0.436f;
            m_V /= 0.615f;
            return this;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public override Color NormalizeToRGBColor()
        {
            return Normalize().ToColor();
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("Color: Y: {0}, U: {1}, V: {2}", m_Y, m_U, m_V);
        }

        /// <summary>
        /// Gets the values.
        /// </summary>
        /// <returns></returns>
        public override object[] GetValues()
        {
            return new object[] { m_Y, m_U, m_V };
        }

        /// <summary>
        /// Sets the values.
        /// </summary>
        /// <param name="_aObject">The _a object.</param>
        public override void SetValues(object[] _aObject)
        {
            this.m_Y = (float)_aObject[0];
            this.m_U = (float)_aObject[1];
            this.m_V = (float)_aObject[2];
        }

        /// <summary>
        /// Create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new YUV(this);
        }
    }
}
